package repo

import (
	"gitee.com/linxing_3/sr-core/domain/dao/scope"
	"gitee.com/linxing_3/sr-core/domain/repo"
	"gitee.com/linxing_3/sr-core/plugins/storage/cache"
	"gitee.com/linxing_3/sr-core/plugins/storage/database"
	"gitee.com/linxing_3/sr-core/yal/ystr"
	"gitee.com/linxing_3/sr-core/yerr"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/acl"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/entity"
	"gitee.com/mkwchecking/sr-admin/version"
)

func NewModuleTable(dataset database.IDataSet, cache cache.ICache) *ModuleTable {
	return &ModuleTable{
		IRepo: repo.NewSet[entity.ModuleTable](dataset, cache),
	}
}

type ModuleTable struct {
	repo.IRepo[entity.ModuleTable]
}

func (s *ModuleTable) AddFields(domain, className string, fields ...*entity.ModuleField) error {
	if len(fields) == 0 {
		return yerr.ErrDataEmpty.Error("fields")
	}
	table := &entity.ModuleTable{
		Domain:    domain,
		ClassName: className,
	}

	fieldsRel, err := s.Association(table, "Fields")
	if err != nil {
		return err
	}

	for _, field := range fields {
		field.ClassName = className
	}

	return fieldsRel.Append(fields)
}

func (s *ModuleTable) Delete(domain, className string, clearFields bool) error {
	ent := &entity.ModuleTable{
		Domain:    domain,
		ClassName: className,
	}

	if clearFields {
		fieldsRel, err := s.Association(ent, "Fields")
		if err != nil {
			return err
		}
		err = fieldsRel.Clear()
		if err != nil {
			return err
		}
	}

	return s.ForceDeleteWithEnt(ent, scope.Where(ent))
}

func (s *ModuleTable) RemoveField(domain, className string, fieldNames ...string) error {
	ent := &entity.ModuleTable{
		Domain:    domain,
		ClassName: className,
	}

	fieldEnts := make([]any, len(fieldNames))
	for i, fieldName := range fieldNames {
		fieldEnts[i] = &entity.ModuleField{
			FieldName: fieldName,
		}
	}

	fieldsRel, err := s.Association(ent, "Fields")
	if err != nil {
		return err
	}

	return fieldsRel.Delete(fieldEnts...)
}

func (s *ModuleTable) ReplaceFields(domain, className string, fields ...*entity.ModuleField) error {
	if len(fields) == 0 {
		return yerr.ErrDataEmpty.Error("fields")
	}
	// table := &entity.ModuleTable{
	// 	Domain:    domain,
	// 	ClassName: className,
	// }

	// fieldsRel, err := s.Association(table, "Fields")
	// if err != nil {
	// 	return err
	// }

	for _, field := range fields {
		field.ClassName = className
		field.Domain = domain
	}

	// return fieldsRel.Replace(fields)
	// s.
	return nil
}

func (s *ModuleTable) GetTplArg(domain, className string) (*acl.TplTable, error) {
	table, err := s.Find(
		s.EntBuilder(func(mt *entity.ModuleTable) {
			mt.Domain = domain
			mt.ClassName = className
		}),
		scope.WithPreload("Fields"),
	)

	if err != nil {
		return nil, err
	}

	return s.ConvertTableToTplArg(table)
}

func (s *ModuleTable) ConvertTableToTplArg(table *entity.ModuleTable) (*acl.TplTable, error) {

	if table.ClassRoute == "" {
		table.ClassRoute = ystr.CaptainLower(ystr.CamelString(table.ClassName))
	}

	if table.DomainRoute == "" {
		table.DomainRoute = ystr.CaptainLower(ystr.CamelString(table.Domain))
	}

	tplTable := &acl.TplTable{
		ClassName:      table.ClassName,
		ClassNameLower: table.ClassRoute,
		ClassRoute:     table.ClassRoute,
		Comment:        table.Comment,
		DomainLower:    ystr.CaptainLower(ystr.CamelString(table.Domain)),
		DomainUpper:    ystr.CamelString(table.Domain),
		DomainRoute:    table.DomainRoute,
		TableName:      table.DBTable,
		AuthCheck:      table.Auth == 1,
		Fields:         make([]*acl.TplField, len(table.Fields)),
		Version:        version.Version,
	}

	for i, field := range table.Fields {

		qs := ""
		if field.QuickSearch != nil {
			qs = field.QuickSearch.Data().String()
		}

		vd := ""
		if field.Validation != nil {
			vd = field.Validation.Data().String()
		}

		tplTable.Fields[i] = &acl.TplField{
			FieldName:   field.FieldName,
			JsonName:    field.JsonName,
			GoType:      field.GoType,
			TsType:      field.TsType,
			Comment:     field.Comment,
			InCreate:    field.InCreate == 1,
			InEdit:      field.InEdit == 1,
			InSearch:    field.InSearch == 1,
			IsPK:        field.IsPk == 1,
			AI:          field.IsPk == 1 && field.GoType == "int",
			IsUnique:    field.IsUnique == 1,
			IsIndex:     field.IsIndex == 1,
			QuickSearch: qs,
			Validation:  vd,
		}

		if field.IsPk == 1 {
			tplTable.PKField = tplTable.Fields[i]
		}
	}
	if tplTable.PKField == nil {
		tplTable.PKField = &acl.TplField{
			FieldName: "Id",
			JsonName:  "id",
			GoType:    "int64",
			TsType:    "number",
			IsPK:      true,
		}
	}

	return tplTable, nil
}
